import {
	RequestUploadBigFile,
	RequestMergeBigFile,
	RequestCheckBigFile,
	RequestAddVedio,
	RequestVedioDeleteById
} from '@/api/path/music'
import { ref, reactive } from 'vue'
import { filterImageUrl, harexsLimit } from '@/utils/index'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getUserFromStore } from '@/common/useStore'
import MyWorkder from '@/utils/webworker?worker'
import axios from 'axios'

// 切片数据
interface IChunkFile {
	file: File
	index: number
	fileName: string
	hash: string
}
const CancelToken = axios.CancelToken
let source = CancelToken.source()
export const useVedio = () => {
	// let controller = new AbortController()
	const initParam = ref({}) // 表格组件初始数据
	const vedioUrl = ref<string>('') // 大文件url地址
	const CHUNK_SIZE = 1024 * 1024 * 3 // 切片大小 3M
	const limitP = harexsLimit(3)
	// 上传进度
	const percentage = reactive<{ value: number; total: number }>({
		value: 0, // 当前值
		total: 0 // 总值
	})
	// 存储上传文件和切片数组数据
	const fileData = reactive<{ file: File; chunkFiles: IChunkFile[] }>({
		file: new File([], ''),
		chunkFiles: []
	})

	/**
	 * 文件上传之前
	 * @param file
	 * @returns
	 */
	const handlerBeforeUpload = (file: File) => {
		const mimeTypes = ['audio/mpeg', 'audio/x-m4a', 'audio/aac', 'video/mp4', 'video/x-m4v']
		if (!mimeTypes.includes(file.type)) {
			ElMessage({
				type: 'error',
				message: '只能上传 MP3、M4A、AAC、MP4、M4V 格式的文件',
				duration: 6000
			})
			return false
		}
		if (file.size / 1024 / 1024 / 1024 > 1.5) {
			ElMessage.error('文件大小不能超过 1.5G')
			ElMessage({
				type: 'error',
				message: '文件大小不能超过 1.5G',
				duration: 6000
			})
			return false
		}
		return true
	}
	/**
	 * 上传大文件
	 */
	const bindUploadBigFile = (raw: any) => {
		const file: File = raw.file //选中文件对象
		fileData.file = file
		startUploadFile(file)
		return Promise.resolve()
	}
	/**
	 * 分片上传
	 */
	const startUploadFile = async (file: File) => {
		let chunkFiles = sliceFile(file) // 切片数组
		percentage.total = chunkFiles.length // 总切片数，实现上传进度
		console.time('myTimer')
		// 获取整个大文件的内容hash
		// const containerHash: any = await calculateHash(chunkFiles)
		// console.log('containerHash ',containerHash);
		// console.timeEnd('myTimer')
		// chunkFiles.forEach((item: IChunkFile) => item.hash = containerHash.hash + '-' + item.index)
		// 断点续传
		let fileList = await fileterFile(file.name, chunkFiles)
		if (fileList.length === 0) {
			percentage.value = chunkFiles.length // 总切片数赋值上传进度，实现上传进度秒传
			ElMessage.success('文件秒传成功!')
			return
		}
		// 构造FormData 携带文件信息
		const formDataList = fileList.map((item: IChunkFile, index: number) => {
			let formData = new FormData()
			formData.append('bigfile', item.file) // 切片文件
			formData.append('fileName', item.fileName) // 完整文件名
			formData.append('chunkName', item.index + '') // 切片名(将 index 作为每一个切片的名字)
			// formData.append('chunkName', item.hash) // 切片名(将 index 作为每一个切片的名字)
			return { formData }
		})
		
		// 并发上传切片
		const requestList = formDataList.map(item =>
			// limitP(() =>
			// 	RequestUploadBigFile(item.formData,).then(() => {
			// 		percentage.value++ // 记录上传切片数，实现上传进度
			// 	})
			// )
			axios({
				url: import.meta.env.VITE_APP_BASE_API+'/api/bigfile',
				headers: { 'Content-Type': 'multipart/form-data',Authorization:localStorage.getItem('TOKEN') || '' },
				data: item.formData,
				method: 'POST',
				cancelToken: source.token,   // 添加 cancelToken，用于后续取消请求发送
			}).then(() => {
				// 每一个切片上传成功后，进度条都 +1
				percentage.value++;
			})
		)
		// 等待所有切片上传完成
		await Promise.all(requestList)
		
		// 合并切片
		mergeFile(file.name)
	}
	/**
	 * 文件切片
	 * @param file
	 * @returns chunkList
	 */
	const sliceFile = (file: File) => {
		// 切片缓存
		if (fileData.chunkFiles && fileData.chunkFiles.length > 0) {
			return fileData.chunkFiles
		}
		const chunkList: IChunkFile[] = [] // 存储切片
		const total = Math.ceil(file.size / CHUNK_SIZE) // 总切片数 CHUNK_SIZE=1024*1024*1 = 1M
		let uploadCount = 0 // 已经上传分片数
		let start = 0 // 开始字节
		let end = CHUNK_SIZE // 结束字节

		while (uploadCount !== total) {
			const newFile: File = <File>file.slice(start, end) // 分片
			chunkList.push({ file: newFile, index: uploadCount, fileName: file.name, hash: '' })
			start = end
			end = start + CHUNK_SIZE
			uploadCount++
		}
		fileData.chunkFiles = chunkList // 切片缓存
		return chunkList
	}
	/**
	 * 断点续传秒传
	 * 已经上传切片与本地切片比较,获取未上传切片
	 * @param fileName 文件名
	 * @param chunkList 所有切片
	 * @returns
	 */
	const fileterFile = async (fileName: string, chunkList: Array<any>) => {
		const data = await RequestCheckBigFile(fileName) // 获取已上传的切片
		const { resultCode, resultInfo } = data
		if (resultCode === 0) {
			return [] //情况1：文件已经上传,秒传情况
		}
		if (resultCode === -1) {
			return chunkList //情况2：文件未上传
		}
		// 情况3：文件上传部份
		percentage.value = resultInfo.length // 已上传切片数， 实现断点续传上传进度
		// 过滤未上传部份切片
		const list = chunkList.filter((item: IChunkFile) => !resultInfo.some((subitem: any) => subitem == item.index))
		return list
	}
	/**
	 * 合并文件
	 */
	const mergeFile = async (filename: string) => {
		const data = await RequestMergeBigFile(CHUNK_SIZE, filename)
		const { resultCode, resultInfo } = data
		if (resultCode === 1) {
			vedioUrl.value = filterImageUrl(resultInfo)
			const account = getUserFromStore()
			bindAddVedio(filename, account.nick, resultInfo, account.mid)
		}
	}

	/**
	 * 计算hash
	 */
	const calculateHash = (fileList: IChunkFile[]) => {
		if (fileList.length > 0 && fileList[0].hash) {
			return fileList[0].hash
		}
		const myWorkder = new MyWorkder()
		return new Promise((resolve, reject) => {
			// 接收子线程内容
			myWorkder.onmessage = ev => {
				resolve(ev.data)
			}
			// 发生错误，终止子线程
			myWorkder.onerror = err => {
				myWorkder.terminate()
				reject(err)
				console.log(err.filename, err.lineno, err.message) // 发生错误的文件名、行号、错误内容
			}
			// 发送信息
			myWorkder.postMessage(fileList)
		})
	}

	/**
	 * 暂停下载
	 */
	const bindPauseDownLoad = () => {
		// 取消后续所有“切片上传”请求的发送
		source.cancel('终止上传！')
		// 重置 source
		source = CancelToken.source()

		// // 在想要中断的地方写到
		// controller.abort()
		// // 重置 controller
		// controller = new AbortController()
	}
	/**
	 * 继续下载
	 */
	const bindGoDownLoad = () => {
		if (fileData.file) {
			startUploadFile(fileData.file)
		}
	}
	/**
	 * 添加视频
	 * @param ev
	 */
	const bindAddVedio = async (title: string, nick: string, url: string, uid: number) => {
		try {
			const data = await RequestAddVedio(title, nick, url, uid)
			const { resultCode } = data
			if (resultCode === 1) {
				ElMessage.success('添加成功!')
				initParam.value = { add: 'success' }
			} else {
				ElMessage.success('添加失败!')
			}
		} catch (err) {
			ElMessage.success('添加失败!' + err)
		}
	}

	/**
	 * 删除视频
	 * @param id
	 */
	const bindDeleteVedio = async (id: number) => {
		const data = await RequestVedioDeleteById(id)
		const { resultCode } = data
		if (resultCode === 1) {
			ElMessage.warning('删除成功!')
			initParam.value = { delete: 'success' }
		}
	}
	/**
	 * 重置
	 */
	const bindResetFileUpload = () => {
		fileData.file = new File([], '')
		fileData.chunkFiles = [] // 重置文件数据
		percentage.value = 0
		percentage.total = 0
		vedioUrl.value = ''
	}
	return {
		vedioUrl,
		percentage,
		initParam,
		bindUploadBigFile,
		handlerBeforeUpload,
		bindResetFileUpload,
		bindDeleteVedio,
		bindPauseDownLoad,
		bindGoDownLoad
	}
}
